<!--
<template>
    <table cellspacing="0" cellpadding="0" border="0" :style="styleObject">
        <colgroup>
            <col v-for="(column, index) in columns" :width="setCellWidth(column)">
        </colgroup>
        <tbody :class="[prefixCls + '-tbody']">
            <template v-for="(row, index) in data">
                <table-tr
                    :draggable="draggable"
                    :row="row"
                    :key="rowKey ? row._rowKey : index"
                    :prefix-cls="prefixCls"
                    @mouseenter.native.stop="handleMouseIn(row._index)"
                    @mouseleave.native.stop="handleMouseOut(row._index)"
                    @click.native="clickCurrentRow(row._index)"
                    @dblclick.native.stop="dblclickCurrentRow(row._index)">
                    <td v-for="(column, colIndex) in columns" :class="alignCls(column, row)" v-bind="getSpan(row, column, index, colIndex)" v-if="showWithSpan(row, column, index, colIndex)">
                        <table-cell
                            :fixed="fixed"
                            :prefix-cls="prefixCls"
                            :row="row"
                            :key="column._columnKey"
                            :column="column"
                            :natural-index="index"
                            :index="row._index"
                            :checked="rowChecked(row._index)"
                            :disabled="rowDisabled(row._index)"
                            :expanded="rowExpanded(row._index)"
                        ></table-cell>
                    </td>
                </table-tr>
                <tr v-if="rowExpanded(row._index)" :class="{[prefixCls + '-expanded-hidden']: fixed}">
                    <td :colspan="columns.length" :class="prefixCls + '-expanded-cell'">
                        <Expand :key="rowKey ? row._rowKey : index" :row="row" :render="expandRender" :index="row._index"></Expand>
                    </td>
                </tr>
            </template>
        </tbody>
    </table>
</template>
-->
<script>
// todo :key="row"
import { h } from 'vue';
import TableTr from './table-tr.vue';
import TableCell from './cell.vue';
import Expand from './expand.js';
import ExpandSlot from './expand-slot.js'
import Mixin from './mixin';

export default {
  name: 'TableBody',
  mixins: [ Mixin ],
  components: { TableCell, Expand, TableTr, ExpandSlot },
  inject: {
    TableInstance: {
      default: null
    }
  },
  props: {
    prefixCls: String,
    styleObject: Object,
    columns: Array,
    data: Array,    // rebuildData
    objData: Object,
    columnsWidth: Object,
    fixed: {
      type: [Boolean, String],
      default: false
    },
    draggable: {
      type: Boolean,
      default: false
    },
    rowKey: {
      type: [Boolean, String],
      default: false
    }
  },
  computed: {
    // 表格expand内容支持render函数渲染
    expandRender () {
      let render = function () {
        return '';
      };
      for (let i = 0; i < this.columns.length; i++) {
        const column = this.columns[i];
        if (column.type && column.type === 'expand') {
          if (column.render) render = column.render;
        }
      }
      return render;
    }
  },
  methods: {
    rowChecked (_index) {
      return this.objData[_index] && this.objData[_index]._isChecked;
    },
    rowDisabled (_index) {
      return this.objData[_index] && this.objData[_index]._isDisabled;
    },
    rowExpanded (_index) {
      return this.objData[_index] && this.objData[_index]._isExpanded;
    },
    rowStatusByRowKey (type, rowKey) {
      const data = this.$parent.getDataByRowKey(rowKey);
      return data[type];
    },
    handleMouseIn (_index, event, rowKey) {
      event.stopPropagation();
      this.$parent.handleMouseIn(_index, rowKey);
    },
    handleMouseOut (_index, event, rowKey) {
      event.stopPropagation();
      this.$parent.handleMouseOut(_index, rowKey);
    },
    clickCurrentRow (_index, event, rowKey) {
      this.$parent.clickCurrentRow(_index, rowKey);
    },
    dblclickCurrentRow (_index, event, rowKey) {
      event.stopPropagation();
      this.$parent.dblclickCurrentRow(_index, rowKey);
    },
    clickCell (row, column, key, event) {
      this.$parent.$emit('on-cell-click', row, column, row[key], event);
    },
    contextmenuCurrentRow (_index, event, rowKey) {
      event.stopPropagation();
      if (this.$parent.contextMenu) event.preventDefault();
      this.$parent.contextmenuCurrentRow(_index, rowKey, event);
    },
    selectStartCurrentRow () {
      if (this.$parent.contextMenu) {
        // event.stopPropagation();
        // event.preventDefault();
      }
    },
    // 行/列合并
    // row: 当前行，column：当前列，rowIndex：当前行索引，columnIndex：当前列索引
    // 返回值: { rowspan: xxx, colspan: xxx }
    getSpan (row, column, rowIndex, columnIndex) {
      const fn = this.$parent.spanMethod; // table.vue中
      if (typeof fn === 'function') {
        const result = fn({
          row,
          column,
          rowIndex,
          columnIndex
        });
        let rowspan = 1;
        let colspan = 1;
        if (Array.isArray(result)) {
          rowspan = result[0];
          colspan = result[1];
        } else if (typeof result === 'object') {
          rowspan = result.rowspan;
          colspan = result.colspan;
        }
        return {
          rowspan,
          colspan
        };
      } else {
        return {};
      }
    },
    showWithSpan (row, column, rowIndex, columnIndex) {
      const result = this.getSpan(row, column, rowIndex, columnIndex);
      return !(('rowspan' in result && result.rowspan === 0) || ('colspan' in result && result.colspan === 0));
    },
    // 当前行数据是否展开
    // 返回boolean
    isTrShow (rowKey) {
      let status = true;
      let child;
      for (let i in this.objData) {
        const row = this.objData[i];
        const showChildren = row._isShowChildren;
        if (row._rowKey === rowKey) {
          status = status && showChildren;
          break;
        } else if (row.children && row.children.length) {
          child = this.getTrStatus(rowKey, row, status && showChildren);
          if (child[0] && child[0]._rowKey === rowKey) {
            return child[1];
          }
        }
      }
      return status;
    },
    getTrStatus (rowKey, data, parentStatus) {
      let status = parentStatus;
      let childData;
      if (data.children && data.children.length) {
        for (let i = 0; i < data.children.length; i++) {
          const row = data.children[i];
          const showChildren = row._isShowChildren;
          if (row._rowKey === rowKey) {
            childData = row;
            status = status && showChildren;
            break;
          } else if (row.children && row.children.length) {
            const child = this.getTrStatus(rowKey, row, status && showChildren);
            if (child[0] && child[0]._rowKey === rowKey) {
              return child;
            }
          }
        }
      }
      return [childData, status];
    },
    // 获取子数据（树形数据）嵌套层级，根据层级设置子数据缩进值
    getLevel (rowKey) {
      let level;
      let child;
      for (let i = 0; i < this.data.length; i++) {
        const row = this.data[i];
        if (row[this.rowKey] === rowKey) {
          level = 0;
          break;
        } else if (row.children && row.children.length) {
          child = this.getChildLevel(row, rowKey, 1);
          if (child[0] && child[0][this.rowKey] === rowKey) {
            return child[1];
          }
        }
      }
      return level;
    },
    // 获取深层子数据（树形数据）
    getChildLevel (data, rowKey, level) {
      let newLevel;
      let childData;
      if (data.children && data.children.length) {
        for (let i = 0; i < data.children.length; i++) {
          const row = data.children[i];
          if (row[this.rowKey] === rowKey) {
            childData = row;
            newLevel = level;
            break;
          } else if (row.children && row.children.length) {
            const child = this.getChildLevel(row, rowKey, level + 1);
            if (child[0] && child[0][this.rowKey] === rowKey) {
              return child;
            }
          }
        }
      }
      return [childData, newLevel];
    },
    // 表格有子数据时（树形结构），渲染子数据
    getChildNode (h, data, nodes) {
      if (data.children && data.children.length) {
        data.children.forEach((row, index) => {
          let $tds = [];

          this.columns.forEach((column, colIndex) => {
            if (this.showWithSpan(row, column, index, colIndex)) {
              const $tableCell = h(TableCell, {
                fixed: this.fixed,
                'prefix-cls': this.prefixCls,
                row: row,
                column: column,
                'natural-index': index,
                index: row._index,
                checked: this.rowStatusByRowKey('_isChecked', row._rowKey),
                disabled: this.rowStatusByRowKey('_isDisabled', row._rowKey),
                expanded: this.rowStatusByRowKey('_isExpanded', row._rowKey),
                treeNode: true,
                treeLevel: this.getLevel(row._rowKey),
                key: column._columnKey,
              });

              const $td = h('td', {
                class: this.alignCls(column, row),
                ...this.getSpan(row, column, index, colIndex),
                onClick: (e) => this.clickCell(row, column, column.key, e)
              }, [$tableCell]);
              $tds.push($td);
            }
          });

          // 判断节点是否展开
          const trStyle = {};
          if (!this.isTrShow(data._rowKey)) trStyle.display = 'none';

          const $tableTr = h(TableTr, {
            draggable: false,
            row: row,
            'prefix-cls': this.prefixCls,
            isChildren: true,
            style: trStyle,
            key: this.rowKey ? row._rowKey : index,
            onMouseenter: (e) => this.handleMouseIn(row._index, e, row._rowKey),
            onMouseleave: (e) => this.handleMouseOut(row._index, e, row._rowKey),
            onClick: (e) => this.clickCurrentRow(row._index, e, row._rowKey),
            onDblclick: (e) => this.dblclickCurrentRow(row._index, e, row._rowKey),
            onContextmenu: (e) => this.contextmenuCurrentRow(row._index, e, row._rowKey),
            onSelectstart: (e) => this.selectStartCurrentRow(row._index, e, row._rowKey)
          }, () => $tds);

          nodes.push($tableTr);

          if (row.children && row.children.length) {
            this.getChildNode(h, row, nodes);
          }
        });
        return nodes;
      } else {
        return nodes;
      }
    }
  },
  render () {
    let $cols = [];
    this.columns.forEach(column => {
      const $col = h('col', {
        width: this.setCellWidth(column)
      });
      $cols.push($col);
    });
    const $colgroup = h('colgroup', {}, $cols);

    let $tableTrs = [];
    this.data.forEach((row, index) => {
      let $tds = [];

      this.columns.forEach((column, colIndex) => {
        if (this.showWithSpan(row, column, index, colIndex)) {
          const $tableCell = h(TableCell, {
            fixed: this.fixed,
            'prefix-cls': this.prefixCls,
            row: row,
            column: column,
            'natural-index': index,
            index: row._index,
            checked: this.rowChecked(row._index),
            disabled: this.rowDisabled(row._index),
            expanded: this.rowExpanded(row._index),
            key: column._columnKey,
          });

          const $td = h('td', {
            class: this.alignCls(column, row),
            ...this.getSpan(row, column, index, colIndex),
            onClick: (e) => this.clickCell(row, column, column.key, e)
          }, [$tableCell]);
          $tds.push($td);
        }
      });

      const $tableTr = h(TableTr, {
        draggable: this.draggable,
        row: row,
        'prefix-cls': this.prefixCls,
        key: this.rowKey ? row._rowKey : index,
        onMouseenter: (e) => this.handleMouseIn(row._index, e),
        onMouseleave: (e) => this.handleMouseOut(row._index, e),
        onClick: (e) => this.clickCurrentRow(row._index, e),
        onDblclick: (e) => this.dblclickCurrentRow(row._index, e),
        onContextmenu: (e) => this.contextmenuCurrentRow(row._index, e),
        onSelectstart: (e) => this.selectStartCurrentRow(row._index, e)
      }, () => $tds);
      $tableTrs.push($tableTr);

      // 表格行数据展开
      if (this.rowExpanded(row._index)) {
        let $Expand = null
        // 支持插槽
        if (this.TableInstance.$slots.expandSlot) {
          $Expand = h(ExpandSlot, {
            row: row,
            column: this.columns,
            index: row._index,
            key: this.rowKey ? row._rowKey : index
          });
        } else {
          // 支持render函数
          $Expand = h(Expand, {
            row: row,
            render: this.expandRender,
            index: row._index,
            key: this.rowKey ? row._rowKey : index
          });
        }
        const $td = h('td', {
          colspan: this.columns.length,
          class: this.prefixCls + '-expanded-cell'
        }, [$Expand]);
        const $tr = h('tr', {
          class: {
            [this.prefixCls + '-expanded-hidden']: this.fixed
          }
        }, [$td]);
        $tableTrs.push($tr);
      }

      // 子数据
      if (row.children && row.children.length) {
        const $childNodes = this.getChildNode(h, row, []);
        $childNodes.forEach(item => {
          $tableTrs.push(item);
        });
      }
    });

    const $tbody = h('tbody', {
      class: this.prefixCls + '-tbody'
    }, [$tableTrs]);

    return h('table', {
      cellspacing: '0',
      cellpadding: '0',
      border: '0',
      style: this.styleObject
    }, [$colgroup, $tbody]);
  }
};
</script>
